package com.strawcom.charmring.view;

import java.util.ArrayList;
import java.util.List;

import org.kymjs.kjframe.widget.ViewHelper;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

import com.strawcom.charmring.R;
import com.strawcom.charmring.util.ScreenUtil;

/**
 * @description 侧拉菜单
 * @author WangPeng
 * @date 2014-12-17
 */
public class SlidingMenu extends HorizontalScrollView {
	/** 屏幕宽度 */
	private int mScreenWidth;
	/** 右侧预留距离dp */
	private int mMenuRightPadding;
	/** 菜单的宽度 */
	private int mMenuWidth;
	/** 菜单的展开隐藏边界 */
	private int mSwtichMenuWidth;
	/** 在被判定为滚动之前用户手指可以移动的最大值。 */
	private int touchSlop;
	/** 标识 */
	private boolean down = false;
	/** 记录按下手指下去时候的X轴滑动起点坐标 */
	private int startScrollX;
	/** 记录按下手指下去时候的X轴坐标 */
	private int downX;
	/** 菜单状态[true打开状态，false隐藏状态] */
	private boolean isOpen = false;
	/** 滑动状态[true正在滑动，false完成滑动] */
	private boolean isAnim = false;
	/** 滑动开关[true开启，false禁止] */
	private boolean isAbleToSliding = true;
	/** 滑动动画时间 此时段内屏蔽SlidingMenu点击事件 */
	static final int ANIM_TIME = 500;

	/** ScollView事件 处理 */
	private int downInterceptX;
	/** ScollView事件 处理 */
	private int downInterceptY;
	/** ScollView事件 处理 */
	private boolean interceptFlag = false;
	/** ScollView事件 处理 */
	private boolean interceptIntent = false;

	private boolean once;

	private ViewGroup mMenu;
	private ViewGroup mContent;

	Handler handler = new Handler();

	public OnSlidingFinishedListener listener;

	public interface OnSlidingFinishedListener {
		void onFinished(boolean isOpen);
	}

	public void setOnSlidingFinishedListener(OnSlidingFinishedListener listener) {
		this.listener = listener;
	}

	public SlidingMenu(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mScreenWidth = ScreenUtil.getScreenWidth(context);
		touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

		TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyle,

		0);
		int n = a.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);
			switch (attr) {
			case R.styleable.SlidingMenu_rightPadding:
				// 默认50
				mMenuRightPadding = a.getDimensionPixelSize(attr,
						(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, getResources().getDisplayMetrics()));
				break;
			}
		}
		a.recycle();
	}

	public SlidingMenu(Context context) {
		this(context, null, 0);
	}

	@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		/** 显示的设置一个宽度 */
		if (!once) {
			LinearLayout wrapper = (LinearLayout) getChildAt(0);
			mMenu = (ViewGroup) wrapper.getChildAt(0);
			mContent = (ViewGroup) wrapper.getChildAt(1);

			mMenuWidth = mScreenWidth - mMenuRightPadding;
			mSwtichMenuWidth = mMenuWidth / 5;
			mMenu.getLayoutParams().width = mMenuWidth;
			mContent.getLayoutParams().width = mScreenWidth;
		}
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			// 将菜单隐藏
			this.scrollTo(mMenuWidth, 0);
			once = true;
		}
	}

	// @Override
	// protected void onDraw(Canvas canvas) {
	// super.onDraw(canvas);
	// // fix bug . slidingMenu auto open . [but this method is not best way]
	// if (!isOpen && Math.abs(getScrollX()) != mMenuWidth) {
	// this.scrollTo(mMenuWidth, 0);
	// }
	// }

	@Override public boolean onInterceptTouchEvent(MotionEvent ev) {
		final boolean deter = true;
		if(deter) return false;  // do not Intercept
		 
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			// LogUtil.d("sildingMenu onInterceptTouchEvent DOWN");
			interceptFlag = false;
			interceptIntent = false;
			downInterceptX = (int) ev.getRawX();
			downInterceptY = (int) ev.getRawY();
			return super.onInterceptTouchEvent(ev);
		case MotionEvent.ACTION_MOVE:
			// LogUtil.d("sildingMenu onInterceptTouchEvent ACTION_MOVE");
			if (!interceptFlag) {
				int moveInterceptX = (int) ev.getRawX() - downInterceptX;
				int moveInterceptY = (int) ev.getRawY() - downInterceptY;

				if (Math.abs(moveInterceptX) < touchSlop && Math.abs(moveInterceptY) < touchSlop) {
					// 距离太小， 不足以判断
					// LogUtil.d("sildingMenu onInterceptTouchEvent 距离太小， 不足以判断");
					return super.onInterceptTouchEvent(ev);
				}

				interceptFlag = true;

				if (downInterceptX < ScreenUtil.getScreenWidth(getContext()) / 6
						&& (downInterceptY > ScreenUtil.getStatusHeight(getContext()) / 8 || downInterceptY < ScreenUtil
								.getStatusHeight(getContext()) / 8 * 7)) {
					// 落点在左侧边缘
					// LogUtil.d("sildingMenu onInterceptTouchEvent 落点在左侧边缘");
					if (Math.abs(moveInterceptX) > 3 * Math.abs(moveInterceptY) && moveInterceptY < 0) {
						// LogUtil.d("sildingMenu onInterceptTouchEvent 意图横向移动, 手指向右");
						interceptIntent = true;
					}
					else {
						// LogUtil.d("sildingMenu onInterceptTouchEvent 意图纵向移动, 或者 手指向左");
						interceptIntent = false;
					}
				}
				else {
					// 中心内容
					interceptIntent = false;
				}
			}
			break;
		}
		return interceptIntent ? super.onInterceptTouchEvent(ev) : false;
	}

	@Override public boolean onTouchEvent(MotionEvent ev) {
		if (!isAnim && isAbleToSliding) {
			int action = ev.getAction();
			switch (action) {
			case MotionEvent.ACTION_DOWN:
				// LogUtils.d("SlidingMenu ACTION_DOWN");
				/**
				 * 记录手指按下时候的X轴坐标 , X轴滑动起点坐标
				 */
				downX = (int) ev.getRawX();
				startScrollX = getScrollX();
				down = true;
				
				for (OnSlidingStateChangedListener l : ssclistenerList) {
					l.onSlidingStart();
				}
				break;
			case MotionEvent.ACTION_MOVE:
				// LogUtils.d("SlidingMenu ACTION_MOVE");
				/**
				 * fix : 从屏幕左侧中间滑动不会触发 onTouchEvent ACTION_DOWN
				 * [原因被leftMenu事件截断]
				 */
				if (!down) {
					downX = (int) ev.getRawX();
					startScrollX = getScrollX();
					down = true;
					
					for (OnSlidingStateChangedListener l : ssclistenerList) {
						l.onSlidingStart();
					}
				}
				break;
			case MotionEvent.ACTION_UP:
				// LogUtils.d("SlidingMenu ACTION_UP");
				/**
				 * fix : 轻触不会触发 onTouchEvent ACTION_MOVE <br>
				 * [原因被轻触屏幕不会触发 ACTION_MOVE]
				 */
				if (!down) {
					downX = (int) ev.getRawX();
					startScrollX = getScrollX();
					down = true;
					
					for (OnSlidingStateChangedListener l : ssclistenerList) {
						l.onSlidingStart();
					}
				}

				int moveScrollX = startScrollX - getScrollX();

				int upX = (int) ev.getRawX();
				if (isOpen && downX < mMenuWidth && Math.abs(downX - upX) < touchSlop) {
					// LogUtil.d("直接点击左侧内容页");
				}
				else if (isOpen && downX >= mMenuWidth && Math.abs(downX - upX) < touchSlop) {
					// LogUtil.d("直接点击右侧内容页"); // 需要放在[想要隐藏 但是移动距离不够]之前判断
					closeMenu(0);
				}
				else if (!isOpen && moveScrollX >= mSwtichMenuWidth) {
					// LogUtil.d("打开 ");
					openMenu(0);
				}
				else if (!isOpen && moveScrollX < mSwtichMenuWidth) {
					// LogUtil.d("想要打开 但是移动距离不够 ");
					closeMenu(0);
				}
				else if (!isOpen && moveScrollX < 0) {
					// LogUtil.d("隐藏状态，手指向左滑");
					closeMenu(0);
				}
				else if (isOpen && -moveScrollX >= mSwtichMenuWidth) {
					// LogUtil.d("隐藏 ");
					closeMenu(0);
				}
				else if (isOpen && -moveScrollX < mSwtichMenuWidth) {
					// LogUtil.d("想要隐藏 但是移动距离不够");
					openMenu(0);
				}
				else if (isOpen && moveScrollX > 0) {
					// LogUtil.d("打开状态 手指向右滑");
					openMenu(0);
				}
				else {
					// LogUtil.d("其他情况 还原"); // 一般不会到这里
					if (isOpen) {
						openMenu(0);
					}
					else {
						closeMenu(0);
					}
				}

				/** 重置按下事件标识 */
				down = false;

				return true;
			}
			return super.onTouchEvent(ev);
		}

		// 动画执行中 或 滑动禁止
		return true;
	}
	
	public void openMenu() {
		for (OnSlidingStateChangedListener l : ssclistenerList) {
			l.onSlidingStart();
		}
		openMenu(0);
	}

	/**
	 * 打开菜单
	 */
	private void openMenu(int flag) {
		this.smoothScrollTo(0, 0);
		isOpen = true;
		letAnimPlay();
	}
	
	public void closeMenu() {
		for (OnSlidingStateChangedListener l : ssclistenerList) {
			l.onSlidingStart();
		}
		closeMenu(0);
	}

	/**
	 * 隐藏菜单
	 */
	private void closeMenu(int flag) {
		this.smoothScrollTo(mMenuWidth, 0);
		isOpen = false;
		letAnimPlay();
	}

	/**
	 * 设置是否开启滑动功能
	 */
	public void setAbleToSliding(boolean able) {
		isAbleToSliding = able;
	}

	/**
	 * 切换菜单状态
	 */
	public void toggle() {
		if (isOpen) {
			closeMenu();
		}
		else {
			openMenu();
		}
	}

	private void letAnimPlay() {
		isAnim = true;
		handler.postDelayed(new Runnable() {
			@Override public void run() {
				isAnim = false;
				if (listener != null) {
					listener.onFinished(isOpen);
				}
				
				for (OnSlidingStateChangedListener l : ssclistenerList) {
					l.onSlidingOver(isOpen);
				}
			}
		}, ANIM_TIME);
	}

	@Override protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		super.onScrollChanged(l, t, oldl, oldt);
		float scale = l * 1.0f / mMenuWidth;
		float leftScale = 1 - 0.3f * scale;
		float rightScale = 0.8f + scale * 0.2f;

		ViewHelper.setScaleX(mMenu, leftScale);
		ViewHelper.setScaleY(mMenu, leftScale);
		ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));
		ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.7f);

		ViewHelper.setPivotX(mContent, 0);
		ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
		ViewHelper.setScaleX(mContent, rightScale);
		ViewHelper.setScaleY(mContent, rightScale);
	}

	private List<OnSlidingStateChangedListener> ssclistenerList = new ArrayList<SlidingMenu.OnSlidingStateChangedListener>();

	public void setOnSlidingStateChangedListener(OnSlidingStateChangedListener listener) {
		if(listener == null) throw new IllegalArgumentException("empty listener");
		ssclistenerList.add(listener);
	}
	
	public void clearOnSlidingStateChangedListener() {
		ssclistenerList.clear();
	}

	public interface OnSlidingStateChangedListener {
		void onSlidingStart();

		void onSlidingOver(boolean isOpened);
	}
}
